#include "curvahermit.h"



//CurvaHermit::CurvaHermit (QGraphicsScene &s) : Curva(s)
CurvaHermit::CurvaHermit (void)
{
}

CurvaHermit::~CurvaHermit()
{
}

void CurvaHermit::makeBezierPoints (void)
{
	_bezierPoints.clear();

	if (_points.size() != _normals.size()) return;

	for (int i = 0; i < _points.size() - 1; ++i)
	{
		_bezierPoints.append (_points[i]);

		_bezierPoints.append (_normals[i]);
		_bezierPoints.append (_points[i + 1] + _points[i + 1] - _normals[i + 1]);
		//_bezierPoints.append (_points[i] + _normals[i]);
		//_bezierPoints.append (_points[i + 1] - _normals[i + 1]);

		_bezierPoints.append (_points[i + 1]);
	}
}

void CurvaHermit::plotSubCurve (QGraphicsScene &s, QPen& p, int index)
{
	QPointF current, next;

	current = _bezierPoints[index];

	double t = 0;
	double aux;

	for (int i = 1; i <= MAX_STEPS; ++i)
	{
		t = i / (double) MAX_STEPS;

		aux = 1.0 - t;

		next = _bezierPoints[index] * (aux*aux*aux);
		next += _bezierPoints[index+1] * (3 * (aux*aux) * (t));
		next += _bezierPoints[index+2] * (3 * (aux) * (t*t));
		next += _bezierPoints[index+3] * (t*t*t);

		_myPlots.append((QGraphicsItem*)s.addLine (QLineF (current, next), p));

		current = next;
	}
}

void CurvaHermit::plotCurve (QGraphicsScene &s, QPen& p)
{
	for (int i = 0; i < _bezierPoints.size() - 3; i += 4)
	{
		plotSubCurve (s, p, i);
	}
}

void CurvaHermit::plotSteps(QGraphicsScene &s, QPen& p)
{
}

void CurvaHermit::plotControls (QGraphicsScene &s, QPen& p)
{
	for (int i = 0; i < _points.size(); ++i)
	{
		_myPlots.append((QGraphicsItem*)s.addEllipse (_points[i].x() - 0.5, _points[i].y() - 0.5, 1, 1, p));

		_myPlots.append((QGraphicsItem*)s.addEllipse (_normals[i].x() - 0.5, _normals[i].y() - 0.5, 1, 1, p));
		//s.addEllipse (_points[i].x() + _normals[i].x() - 0.5, _points[i].y() + _normals[i].y() - 0.5, 1, 1, p);
	}
}

void CurvaHermit::plotFecho(QGraphicsScene &s, QPen& p)
{
	int r = 200-_plotColor.red();
	int g = 200-_plotColor.green();
	int b = 200-_plotColor.blue();

	p.setColor(QColor(r>=0?r:0, g>=0?g:0, b>=0?b:0));


	for( int i = 0; i < _points.size(); ++i)
	{
		_myPlots.append(s.addLine(QLineF(_points[i], _normals[i]), p));
	}
}

void CurvaHermit::plot (QGraphicsScene &s, QPen& p, RenderMode renderMode)
{
	makeBezierPoints();

	QColor prevColor = p.color();

	p.setColor(_plotColor);

	switch(renderMode)
	{
		case CurveMode:
			plotCurve(s, p);
			break;
		case StepMode:
			plotSteps(s, p);
			break;
		case ControlMode:
			plotControls(s, p);
			break;
		case FechoConvexo:
			plotFecho(s, p);
			break;
	}

	p.setColor(prevColor);
}

bool CurvaHermit::validate (void)
{
	qDebug() << "Points : " << _points.size() << " Normals : " << _normals.size();
	return (_points.size() == _normals.size() && _points.size() >= 2);
}

bool CurvaHermit::minimumValidate (void)
{
	return (_points.size() == _normals.size() && _points.size() >= 2);
}

void CurvaHermit::read (QDomElement node)
{
	QDomElement p = node.firstChildElement();

	qDebug() << "Loading Hermit Curve...";

	while(!p.isNull())
	{
		if( p.tagName() == "ponto")
		{
			QPointF point;
			QPointF normal;

			QDomElement coords = p.firstChildElement();

			while( !coords.isNull())
			{
				if( coords.tagName() == "x")
				{
					QString t = coords.text();
					point.setX(t.toDouble());
				}
				else if( coords.tagName() == "y" )
				{
					QString t = coords.text();
					point.setY(t.toDouble());
				}
				else if( coords.tagName() == "tangente" )
				{
					normal = readPoint(coords);
				}
				else
				{
					qDebug() << "\t" <<  "Unknow Tag name " << coords.tagName() << " inside Hermit Curve's \"ponto\" Tag";
				}
				coords = coords.nextSiblingElement();
			}

			_points.append(point);
			_normals.append(normal);
		}
		else if( p.tagName() == "cor")
		{
			QColor c = readColor(p);

			_plotColor = c;
		}
		else
		{
			qDebug() << "\t" << "Unknow Tag Name inside Bezier Curve : " << p.tagName();
		}

		p = p.nextSiblingElement();
	}

	for (int i = 0; i < _normals.size(); ++i)
	{
		_normals[i] += _points[i];
	}
}

QDomElement CurvaHermit::save(QDomDocument doc)
{
	QDomElement me = doc.createElement("curva");

	me.setAttribute("formato", "hermit");
	me.setAttribute("resolucao", MAX_STEPS);

	for( int i = 0; i < _points.size(); ++i )
	{
		QPointF p = _points[i];

		QDomElement point = doc.createElement("ponto");

		// X
		QDomElement x = doc.createElement("x");
		QDomElement y = doc.createElement("y");

		QDomCharacterData xValue = doc.createTextNode(QString::number(p.x()));
		QDomCharacterData yValue = doc.createTextNode(QString::number(p.y()));

		x.appendChild(xValue);
		y.appendChild(yValue);

		point.appendChild(x);
		point.appendChild(y);

		// Tangente
		{
			QDomElement tan = doc.createElement("tangente");

			// X
			QDomElement tanX = doc.createElement("x");
			QDomElement tanY = doc.createElement("y");

			QDomCharacterData tanXValue = doc.createTextNode(QString::number(_normals[i].x() - _points[i].x()));
			QDomCharacterData tanYValue = doc.createTextNode(QString::number(_normals[i].y() - _points[i].y()));

			tanX.appendChild(tanXValue);
			tanY.appendChild(tanYValue);

			tan.appendChild(tanX);
			tan.appendChild(tanY);

			point.appendChild(tan);
		}

		me.appendChild(point);
	}

	// Cor
	QDomElement cor = doc.createElement("cor");

	QDomElement corR = doc.createElement("r");
	QDomElement corG = doc.createElement("g");
	QDomElement corB = doc.createElement("b");

	QDomCharacterData corRValue = doc.createTextNode(QString::number(_plotColor.red()));
	QDomCharacterData corGValue = doc.createTextNode(QString::number(_plotColor.green()));
	QDomCharacterData corBValue = doc.createTextNode(QString::number(_plotColor.blue()));

	corR.appendChild( corRValue );
	corG.appendChild( corGValue );
	corB.appendChild( corBValue );

	cor.appendChild(corR);
	cor.appendChild(corG);
	cor.appendChild(corB);

	me.appendChild(cor);

	return me;
}

void CurvaHermit::addPoint (QPointF p)
{
	_points.append (p);
	_normals.append (p + QPointF (16.0, 0.0));
}

int CurvaHermit::removePoint (QPointF* p)
{
	for (int i = 0; i < _points.size(); ++i)
	{
		if (p == &(_points[i]) || p == &(_normals[i]))
		{
			_points.remove (i);
			_normals.remove (i);
			return true; //!(_points.size()) | 0x2;
		}
	}

	return false; //!(_points.size());
}

void CurvaHermit::clear (QGraphicsScene &s)
{
	for( int i = 0; i < _myPlots.size(); ++i )
	{
		s.removeItem(_myPlots[i]);
		delete _myPlots[i];
	}

	_myPlots.clear();
}

QPointF* CurvaHermit::selectPoint (QPointF &p, const double precision)
{
	QPointF diff;

	for (int i = 0; i < _points.size(); ++i)
	{
		diff = _points[i] - p;
		diff.setX (diff.x() * diff.x());
		diff.setY (diff.y() * diff.y());

		if (diff.manhattanLength() <= precision)
			return &(_points[i]);

		diff = _normals[i] - p;
		diff.setX (diff.x() * diff.x());
		diff.setY (diff.y() * diff.y());

		if (diff.manhattanLength() <= precision)
			return &(_normals[i]);
	}

	return NULL;
}

QImage CurvaHermit::draw()
{
	// STUB
	return QImage();
}

